import static org.junit.Assert.*;


import org.junit.Before;
import org.junit.Test;


public class VendingMachineTest {

	VendingMachine machine1;
	VendingMachine machine2;
	VendingMachine machine3;
	VendingMachineItem item1;
	@Before
	public void setUp() throws Exception {
		machine1 = new VendingMachine();
		machine2 = new VendingMachine();
		machine3 = new VendingMachine();
		item1 = new VendingMachineItem("A",1);
	}
	@Test(expected=VendingMachineException.class)
	public void testAddItem() {
		//Test precondition
		assertNull(machine1.getItem(VendingMachine.A_CODE));
		machine1.addItem(item1,VendingMachine.A_CODE);
		//Test postcondition
		assertEquals(item1, machine1.getItem(VendingMachine.A_CODE));
		//Test exception case
		machine1.addItem(item1,VendingMachine.A_CODE);
	}

	@Test(expected=VendingMachineException.class)
	public void testRemoveItem() {
		machine1.addItem(item1, VendingMachine.B_CODE);
		//Item exist before removing (code slot is not empty)
		assertEquals(item1, machine1.getItem(VendingMachine.B_CODE));
		assertEquals(item1, machine1.removeItem(VendingMachine.B_CODE));
		//Test if it is removed or not
		assertNull(machine1.getItem(VendingMachine.B_CODE));
		//Exception test invalid code
		machine1.removeItem("INVALID_CODE");
		//Exception test empty slot
		machine1.removeItem(VendingMachine.B_CODE);
		machine1.removeItem(VendingMachine.C_CODE);
		
		
	}

	@Test(expected=VendingMachineException.class)
	public void testInsertMoney() {
		//Precondition check by exception
		machine1.insertMoney(-2.00);
		double previousBalance = machine1.getBalance();
		machine1.insertMoney(2.0);
		assertTrue(previousBalance + 2.0 -  machine1.getBalance() == 0);
	}

	@Test
	public void testGetBalance() {
		//Use Machine 2 as a new machine to test beginning balance
		assertTrue(machine2.getBalance()==0);
		//check postcondition.
		assertTrue(machine2.getBalance()==0);
		double money = 2.5;
		//insert some money and check new balance.
		machine2.insertMoney(money);
		//check change in balance.
		assertTrue(machine2.getBalance()-money == 0);
		//check postcondition again.
		assertTrue(machine2.getBalance()-money == 0);
	}

	@Test
	public void testMakePurchase() {
		//test precondition
		assertTrue(machine1.getBalance() >=0);
		//Add an item
		machine1.addItem(new VendingMachineItem("gum",1.00),VendingMachine.C_CODE);
		//Add $2 to machine.
		machine1.insertMoney(2.00);
		assertTrue(machine1.getBalance()-2.00 == 0);
		//Check if item can be purchased.
		assertTrue(machine1.makePurchase(VendingMachine.C_CODE));		
		//Check the balance
		assertTrue(machine1.getBalance()-1.00 == 0);
		
		//Check null data, try to buy the same item.
		assertFalse(machine1.makePurchase(VendingMachine.C_CODE));		
		//add expensive item and try to buy with less money.
		machine1.addItem(new VendingMachineItem("ExpensiveGum",10.00),VendingMachine.D_CODE);
		assertFalse(machine1.makePurchase(VendingMachine.D_CODE));
	}

	@Test
	public void testReturnChange() {
		//test precondition
		assertTrue(machine3.getBalance() >=0);
		//Add an item
		machine3.addItem(new VendingMachineItem("gum",1.00),VendingMachine.A_CODE);
		//Add $2 to machine.
		machine3.insertMoney(2.00);
		//Make first purchase
		assertTrue(machine3.getBalance() - 2 == 0); //Before purchase balance is 2
		machine3.makePurchase(VendingMachine.A_CODE);
		assertTrue(machine3.getBalance() - 1 == 0);//After purchase balance is 1
		assertTrue(machine3.returnChange() - 1 == 0);//change is 1
		assertTrue(machine3.getBalance() == 0);		//After returning change, balance is 0
	}
}
